package com.luolc.litesyllabusview.view;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Typeface;
import android.support.v4.content.ContextCompat;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;

import com.luolc.litesyllabusview.R;
import com.luolc.litesyllabusview.entity.LiteCourse;

import java.security.InvalidParameterException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Created by Liangchen Luo on 16/2/11, with awful network status.
 *
 * @author Liangchen Luo
 */
public class LiteSyllabusView extends LinearLayout {

    private static final String[] WEEKDAY_TITLES = {"星期一", "星期二", "星期三", "星期四", "星期五", "星期六", "星期天"};
    private static final int[] COURSE_BACKGROUND_COLOR_RES_DEFAULT = {
            R.color.bgCourse0,
            R.color.bgCourse1,
            R.color.bgCourse2,
            R.color.bgCourse3,
            R.color.bgCourse4,
            R.color.bgCourse5,
            R.color.bgCourse6,
            R.color.bgCourse7,
            R.color.bgCourse8,
            R.color.bgCourse9,
            R.color.bgCourse10,
            R.color.bgCourse11,
            R.color.bgCourse12,
            R.color.bgCourse13,
            R.color.bgCourse14
    };
    private static final int HEIGHT_DEFAULT = 640;
    private static final int HEADER_HEIGHT_DEFAULT = 24;
    private static final int SIDEBAR_WIDTH_DEFAULT = 16;
    private static final float DIVIDER_WIDTH_DEFAULT = 0.5f;
    private static final float DIVIDER_HEIGHT_DEFAULT = 0.5f;
    private static final int WEEKDAY_NUMBER_DEFAULT = 7;
    private static final int WEEKDAY_NUMBER_WITHOUT_WEEKEND = 5;
    private static final int SECTION_NUMBER_DEFAULT = 12;
    private static final int WEEKDAY_TITLE_TEXT_SIZE = 14;
    private static final int SECTION_SIDEBAR_TEXT_SIZE = 14;

    private Context mContext;

    private int mWeekdayNumber;
    private int mSectionNumber;

    private int mWidth;
    private int mHeight;
    private int mSectionWidth;
    private int mSectionHeight;
    private int mWeekdayHeaderHeight;
    private int mSectionSidebarWidth;
    private int mDividerWidth;
    private int mDividerHeight;
    private Typeface mTitleTypeface;

    private int mCourseNameTextSize;
    private int mCoursePositionTextSize;
    private int mCourseNoteTextSize;

    private LinearLayout layoutWeekdayHeader;
    private LinearLayout layoutSectionSidebar;
    private LinearLayout layoutCourseTable;

    private OnBlankViewClickListener mOnBlankViewClickListener;

    private List<LiteCourse> mLiteCourses = new ArrayList<>();
    private int[] mCourseBackgroundColorPalette;

    public interface OnBlankViewClickListener {
        void onClick(View view, int weekday, int section);

        void onLongClick(View view, int weekday, int section);
    }

    public LiteSyllabusView(Context context) {
        this(context, null);
    }

    public LiteSyllabusView(Context context, AttributeSet attributeSet) {
        this(context, attributeSet, 0);
    }

    public LiteSyllabusView(Context context, AttributeSet attributeSet, int defStyle) {
        super(context, attributeSet, defStyle);
        mContext = context;
        mWeekdayNumber = WEEKDAY_NUMBER_DEFAULT;
        mSectionNumber = SECTION_NUMBER_DEFAULT;
        mWidth = getScreenWidth();
        mHeight = dip2px(HEIGHT_DEFAULT);
        mDividerWidth = dip2px(DIVIDER_WIDTH_DEFAULT);
        mDividerHeight = dip2px(DIVIDER_HEIGHT_DEFAULT);
        mWeekdayHeaderHeight = dip2px(HEADER_HEIGHT_DEFAULT);
        mSectionSidebarWidth = dip2px(SIDEBAR_WIDTH_DEFAULT);
        mCourseNameTextSize = CourseView.NAME_TEXT_SIZE_DEFAULT;
        mCoursePositionTextSize = CourseView.POSITION_TEXT_SIZE_DEFAULT;
        mCourseNoteTextSize = CourseView.NOTE_TEXT_SIZE_DEFAULT;
        try {
            mTitleTypeface = Typeface.createFromAsset(mContext.getAssets(), "fonts/ChalkboardSE.ttc");
        } catch (RuntimeException e) {
            e.printStackTrace();
        }
        mOnBlankViewClickListener = new OnBlankViewClickListener() {
            @Override
            public void onClick(View view,int weekday, int section) {
            }

            @Override
            public void onLongClick(View view,int weekday, int section) {
            }
        };

        setDefaultColorPalette();
        setOrientation(VERTICAL);
    }

    public void clear() {
        mLiteCourses.clear();
    }

    public void show() {
        calculateSectionSize();
        generateCourseBackground();
        setupView();
        invalidate();
    }

    public void setCourses(List<LiteCourse> data) {
        mLiteCourses.clear();
        if (data == null) return;
        mLiteCourses.addAll(data);
    }

    public void addCourse(LiteCourse liteCourse) {
        if (liteCourse == null) return;
        if (isCourseSectionRepeatConflict(liteCourse)) {
            Toast.makeText(mContext, "课程有冲突。。", Toast.LENGTH_SHORT).show();
        } else {
            mLiteCourses.add(liteCourse);
        }
    }

    public void removeCourseById(String id) {
        for (LiteCourse liteCourse : mLiteCourses) {
            if (id.equals(liteCourse.getCourseId())) mLiteCourses.remove(liteCourse);
        }
    }

    public void setSectionNumber(int sectionNumber) throws IllegalArgumentException {
        if (sectionNumber <= 0)
            throw new IllegalArgumentException("Section number must be positive");
        mSectionNumber = sectionNumber;
    }

    public void setCourseBackgroundColors(int[] colors) {
        mCourseBackgroundColorPalette = colors;
    }

    public void setCourseNameTextSize(int textSize) {
        mCourseNameTextSize = textSize;
    }

    public void setCoursePositionTextSize(int textSize) {
        mCoursePositionTextSize = textSize;
    }

    public void setCourseNoteTextSize(int textSize) {
        mCourseNoteTextSize = textSize;
    }

    public void setOnBlankViewClickListener(OnBlankViewClickListener listener) {
        mOnBlankViewClickListener = listener;
    }

    public void hideWeekendColumn(boolean what) {
        if (what) {
            mWeekdayNumber = WEEKDAY_NUMBER_WITHOUT_WEEKEND;
        } else {
            mWeekdayNumber = WEEKDAY_NUMBER_DEFAULT;
        }
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
    }

    private void setDefaultColorPalette() {
        int size = COURSE_BACKGROUND_COLOR_RES_DEFAULT.length;
        mCourseBackgroundColorPalette = new int[size];
        for (int i = 0; i < size; ++i) {
            int color = ContextCompat.getColor(mContext, COURSE_BACKGROUND_COLOR_RES_DEFAULT[i]);
            mCourseBackgroundColorPalette[i] = color;
        }
    }

    private void calculateSectionSize() {
        mSectionWidth = (mWidth - mSectionSidebarWidth - mWeekdayNumber * mDividerWidth) / mWeekdayNumber;
        mSectionHeight = (mHeight - mWeekdayHeaderHeight - mSectionNumber * mDividerHeight) / mSectionNumber;
    }

    private void generateCourseBackground() {
        int currentColorIndex = 0;
        int paletteSize = mCourseBackgroundColorPalette.length;
        Map<String, Integer> nameColorMap = new HashMap<>();
        if (mLiteCourses == null) mLiteCourses = new ArrayList<>();
        for (LiteCourse liteCourse : mLiteCourses) {
            if (nameColorMap.containsKey(liteCourse.getName())) {
                liteCourse.setBackgroundColor(nameColorMap.get(liteCourse.getName()));
            } else {
                int color = mCourseBackgroundColorPalette[currentColorIndex % paletteSize];
                nameColorMap.put(liteCourse.getName(), color);
                liteCourse.setBackgroundColor(color);
                currentColorIndex++;
            }
        }
    }

    private void setupView() {
        removeAllViews();
        setupWeekdayHeader();
        setupSectionSidebar();
        setupCourseTable();

        LinearLayout layoutBottom = new LinearLayout(mContext);
        layoutBottom.setOrientation(HORIZONTAL);
        layoutBottom.addView(layoutSectionSidebar);
        layoutBottom.addView(layoutCourseTable);

        addView(layoutWeekdayHeader);
        addView(layoutBottom);
    }

    private void setupWeekdayHeader() {
        layoutWeekdayHeader = new LinearLayout(mContext);
        layoutWeekdayHeader.setOrientation(HORIZONTAL);
        ViewGroup.LayoutParams params = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, mWeekdayHeaderHeight);
        layoutWeekdayHeader.setLayoutParams(params);

        TextView tvEmptyCellOnTopAndLeft = new TextView(mContext);
        tvEmptyCellOnTopAndLeft.setWidth(mSectionSidebarWidth);
        tvEmptyCellOnTopAndLeft.setHeight(mWeekdayHeaderHeight);
        tvEmptyCellOnTopAndLeft.setText("\\");
        tvEmptyCellOnTopAndLeft.setTextSize(WEEKDAY_TITLE_TEXT_SIZE);
        tvEmptyCellOnTopAndLeft.setTextColor(ContextCompat.getColor(mContext, R.color.textTitle));
        tvEmptyCellOnTopAndLeft.setGravity(Gravity.CENTER);
        tvEmptyCellOnTopAndLeft.setTypeface(mTitleTypeface);
        layoutWeekdayHeader.addView(tvEmptyCellOnTopAndLeft);

        for (int i = 0; i < mWeekdayNumber; ++i) {
            layoutWeekdayHeader.addView(getVerticalDividerView());
            TextView tvWeekdayTitle = new TextView(mContext);
            tvWeekdayTitle.setWidth(mSectionWidth);
            tvWeekdayTitle.setHeight(mWeekdayHeaderHeight);
            tvWeekdayTitle.setText(WEEKDAY_TITLES[i]);
            tvWeekdayTitle.setTextSize(WEEKDAY_TITLE_TEXT_SIZE);
            tvWeekdayTitle.setTextColor(ContextCompat.getColor(mContext, R.color.textTitle));
            tvWeekdayTitle.setGravity(Gravity.CENTER);
            tvWeekdayTitle.setTypeface(mTitleTypeface);
            layoutWeekdayHeader.addView(tvWeekdayTitle);
        }

        layoutWeekdayHeader.setBackgroundColor(ContextCompat.getColor(mContext, R.color.bgWeekdayHeader));
    }

    private void setupSectionSidebar() {
        layoutSectionSidebar = new LinearLayout(mContext);
        layoutSectionSidebar.setOrientation(VERTICAL);
        ViewGroup.LayoutParams params = new ViewGroup.LayoutParams(mSectionSidebarWidth, ViewGroup.LayoutParams.MATCH_PARENT);
        layoutSectionSidebar.setLayoutParams(params);

        for (int i = 1; i <= mSectionNumber; ++i) {
            layoutSectionSidebar.addView(getHorizontalDividerView());
            TextView tvSectionNumberTitle = new TextView(mContext);
            tvSectionNumberTitle.setWidth(mSectionSidebarWidth);
            tvSectionNumberTitle.setHeight(mSectionHeight);
            tvSectionNumberTitle.setText("" + i);
            tvSectionNumberTitle.setTextSize(SECTION_SIDEBAR_TEXT_SIZE);
            tvSectionNumberTitle.setTextColor(ContextCompat.getColor(mContext, R.color.textTitle));
            tvSectionNumberTitle.setGravity(Gravity.CENTER);
            tvSectionNumberTitle.setTypeface(mTitleTypeface);
            layoutSectionSidebar.addView(tvSectionNumberTitle);
        }

        layoutSectionSidebar.setBackgroundColor(ContextCompat.getColor(mContext, R.color.bgSectionSidbar));
    }

    private void setupCourseTable() {
        layoutCourseTable = new LinearLayout(mContext);
        layoutCourseTable.setOrientation(HORIZONTAL);

        for (int i = 0; i < mWeekdayNumber; ++i) {
            layoutCourseTable.addView(getVerticalDividerView());
            layoutCourseTable.addView(getCourseViewColumn(i));
        }
    }

    /**
     * 创建一天的课程
     *
     * @param weekday 当前日期
     * @return 当前日期的课程
     * @throws InvalidParameterException
     */
    private LinearLayout getCourseViewColumn(final int weekday) throws InvalidParameterException {
        //创建当前日期的root层
        LinearLayout layoutColumn = new LinearLayout(mContext);
        layoutColumn.setOrientation(VERTICAL);
        ViewGroup.LayoutParams params = new ViewGroup.LayoutParams(mSectionWidth, ViewGroup.LayoutParams.MATCH_PARENT);
        layoutColumn.setLayoutParams(params);
        //获取当前日期的课程
        List<LiteCourse> coursesInCurrentDay = new ArrayList<>();
        if (mLiteCourses == null) mLiteCourses = new ArrayList<>();
        for (LiteCourse liteCourse : mLiteCourses) {
            if (liteCourse.getWeekday() == weekday) {
                coursesInCurrentDay.add(liteCourse);
            }
        }
        //根据，起始“节数”排序，从小到大
        Collections.sort(coursesInCurrentDay, new Comparator<LiteCourse>() {
            @Override
            public int compare(LiteCourse lhs, LiteCourse rhs) {
                return Integer.valueOf(lhs.getStartSection()).compareTo(rhs.getStartSection());
            }
        });
        //如果下一个课程的起始日期小于或等于上一个结束，那么抛出错误
        for (int i = 1; i < coursesInCurrentDay.size(); ++i) {
            if (coursesInCurrentDay.get(i).getStartSection() <= coursesInCurrentDay.get(i - 1).getEndSection()) {
                throw new InvalidParameterException("CN：课程时间冲突（EN：There are duration conflicts among courses）");
            }
        }
        for (int i = 0; i < coursesInCurrentDay.size(); ++i) {
            int blankSectionStartPosition;
            LiteCourse liteCourse = coursesInCurrentDay.get(i);
            if (i == 0) {
                blankSectionStartPosition = 1;
            } else {
                blankSectionStartPosition = coursesInCurrentDay.get(i - 1).getEndSection() + 1;
            }
            // 添加每节课前空课时View
            for (int j = blankSectionStartPosition; j < liteCourse.getStartSection(); ++j) {
                layoutColumn.addView(getHorizontalDividerView());
                final int section = j;
                CourseView blankCourseView = new CourseView.Builder(mContext)
                        .setSectionWidth(mSectionWidth)
                        .setSectionHeight(mSectionHeight)
                        .setSection(section)
                        .setWeekday(weekday)
                        .setOnClickListener(new OnClickListener() {
                            @Override
                            public void onClick(View v) {
                                mOnBlankViewClickListener.onClick(v,weekday, section);
                            }
                        })
                        .setOnLongClickListener(new OnLongClickListener() {
                            @Override
                            public boolean onLongClick(View v) {
                                mOnBlankViewClickListener.onLongClick(v,weekday, section);
                                return true;
                            }
                        })
                        .createBlankSection();
                layoutColumn.addView(blankCourseView);
            }
            // 添加position为i的课的View
            layoutColumn.addView(getHorizontalDividerView());
            CourseView courseView = new CourseView.Builder(mContext)
                    .setSectionWidth(mSectionWidth)
                    .setSectionHeight(mSectionHeight)
                    .setName(liteCourse.getName())
                    .setPosition(liteCourse.getPosition())
                    .setNote(liteCourse.getNote())
                    .setNameTextSize(mCourseNameTextSize)
                    .setPositionTextSize(mCoursePositionTextSize)
                    .setNoteTextSize(mCourseNoteTextSize)
                    .setStartSection(liteCourse.getStartSection())
                    .setEndSection(liteCourse.getEndSection())
                    .setWeekday(weekday)
                    .setBackgroundColor(liteCourse.getBackgroundColor())
                    .setActive(liteCourse.isActive())
                    .setOnClickListener(liteCourse.getOnClickListener())
                    .setOnLongClickListener(liteCourse.getOnLongClickListener())
                    .create();
            courseView.setTag(liteCourse);
            FrameLayout courseFrame = new FrameLayout(mContext);
            courseFrame.addView(courseView);
            courseFrame.setBackgroundResource(R.drawable.litesyllabusview_shade);
            layoutColumn.addView(courseFrame);
            // 如果是当天最后一节课，添加末尾的空课时View
            if (i == coursesInCurrentDay.size() - 1) {
                blankSectionStartPosition = liteCourse.getEndSection() + 1;
                for (int j = blankSectionStartPosition; j <= mSectionNumber; ++j) {
                    layoutColumn.addView(getHorizontalDividerView());
                    final int section = j;
                    CourseView blankCourseView = new CourseView.Builder(mContext)
                            .setSectionWidth(mSectionWidth)
                            .setSectionHeight(mSectionHeight)
                            .setSection(section)
                            .setWeekday(weekday)
                            .setOnClickListener(new OnClickListener() {
                                @Override
                                public void onClick(View v) {
                                    mOnBlankViewClickListener.onClick(v,weekday, section);
                                }
                            })
                            .setOnLongClickListener(new OnLongClickListener() {
                                @Override
                                public boolean onLongClick(View v) {
                                    mOnBlankViewClickListener.onLongClick(v,weekday, section);
                                    return true;
                                }
                            })
                            .createBlankSection();
                    layoutColumn.addView(blankCourseView);
                }
            }
        }
        //如果当天没有课程
        if (coursesInCurrentDay.isEmpty()) {
            for (int i = 1; i <= mSectionNumber; ++i) {
                layoutColumn.addView(getHorizontalDividerView());
                final int section = i;
                CourseView blankCourseView = new CourseView.Builder(mContext)
                        .setSectionWidth(mSectionWidth)
                        .setSectionHeight(mSectionHeight)
                        .setSection(section)
                        .setWeekday(weekday)
                        .setOnClickListener(new OnClickListener() {
                            @Override
                            public void onClick(View v) {
                                mOnBlankViewClickListener.onClick(v,weekday, section);
                            }
                        })
                        .setOnLongClickListener(new OnLongClickListener() {
                            @Override
                            public boolean onLongClick(View v) {
                                mOnBlankViewClickListener.onLongClick(v,weekday, section);
                                return true;
                            }
                        })
                        .createBlankSection();
                layoutColumn.addView(blankCourseView);
            }
        }
        return layoutColumn;
    }


    /**
     * 课程冲突检测
     *
     * @param insertCourse 课程实体
     * @return true 有冲突 false 没有冲突
     */
    private boolean isCourseSectionRepeatConflict(LiteCourse insertCourse) {
        //获取当前日期的课程
        List<LiteCourse> coursesInCurrentDay = new ArrayList<>();
        if (mLiteCourses == null) mLiteCourses = new ArrayList<>();
        coursesInCurrentDay.add(insertCourse);
        for (LiteCourse liteCourse : mLiteCourses) {
            if (liteCourse.getWeekday() == insertCourse.getWeekday()) {
                coursesInCurrentDay.add(liteCourse);
            }
        }

        //根据，起始“节数”排序，从小到大
        Collections.sort(coursesInCurrentDay, new Comparator<LiteCourse>() {
            @Override
            public int compare(LiteCourse lhs, LiteCourse rhs) {
                return Integer.valueOf(lhs.getStartSection()).compareTo(rhs.getStartSection());
            }
        });
        //插入的课程的位置
        int position = coursesInCurrentDay.indexOf(insertCourse);
        if (insertCourse.getStartSection() <= coursesInCurrentDay.get(position - 1).getEndSection() ||
                insertCourse.getEndSection() >= coursesInCurrentDay.get(position + 1).getStartSection()) {
            //CN：课程时间冲突（EN：There are duration conflicts among courses）
            return true;
        }
        return false;
    }

    private View getVerticalDividerView() {
        View divider = new View(mContext);
        divider.setBackgroundColor(ContextCompat.getColor(mContext, R.color.divider));
        ViewGroup.LayoutParams params = new ViewGroup.LayoutParams(mDividerWidth, ViewGroup.LayoutParams.MATCH_PARENT);
        divider.setLayoutParams(params);
        return divider;
    }

    private View getHorizontalDividerView() {
        View divider = new View(mContext);
        divider.setBackgroundColor(ContextCompat.getColor(mContext, R.color.divider));
        ViewGroup.LayoutParams params = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, mDividerHeight);
        divider.setLayoutParams(params);
        return divider;
    }

    private int getScreenWidth() {
        return mContext.getResources().getDisplayMetrics().widthPixels;
    }

    private int dip2px(float dpValue) {
        final float scale = mContext.getResources().getDisplayMetrics().density;
        return (int) (dpValue * scale + 0.5f);
    }
}
